package com.yangjie.common.syslog;

import java.lang.reflect.Method;

import javax.inject.Inject;

import org.apache.log4j.Logger;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;

import com.yangjie.common.DomainUtils;

@Aspect
@Order(value=99)
public class OperationLogger {
	Logger logger = Logger.getLogger(this.getClass());
	@Inject
	private SysLogService service = null;
	
	@Inject
	LogMessageProvider messageProvider = null; 
	private String getDomainName(ProceedingJoinPoint joinPoint) {
		String targetClassName = joinPoint.getTarget().getClass().getName();
		return DomainUtils.getDomainName(targetClassName);
	}
	
//	private SysLog makeLog(String messageCode, String domainName, Object[] args) {
//		SysLog log = new SysLog();
//		String i18nDomainName = messageProvider.getMessage("domain." + domainName);
//		Object[] messageArgs = null;
//		if(args != null) {
//			messageArgs = new Object[args.length + 1];
//		} else {
//			messageArgs = new Object[]{domainName};
//		}
//		String logMessage = messageProvider.getMessage(messageCode, messageArgs);
//		log.setLog(logMessage);
//		return log;
//	}
	
	private SysLog makeCreateLog(String messageCode, String domainName, Object[] args) {
		SysLog log = new SysLog();
		String i18nDomainName = messageProvider.getMessage("domain." + domainName);
		
		String logMessage = messageProvider.getMessage(messageCode, new Object[]{i18nDomainName, args[0].toString()});
		log.setLog(logMessage);
		return log;
	}
	
	private SysLog makeQueryLog(String messageCode, String domainName, Object[] args) {
		SysLog log = new SysLog();
		String i18nDomainName = messageProvider.getMessage("domain." + domainName);
		String logMessage = messageProvider.getMessage(messageCode, new Object[]{i18nDomainName});
		log.setLog(logMessage);
		return log;
	}
	
	private SysLog makeDeleteLog(String messageCode, String domainName, Object[] args) {
		SysLog log = new SysLog();
		String i18nDomainName = messageProvider.getMessage("domain." + domainName);
		String logMessage = messageProvider.getMessage(messageCode, new Object[]{i18nDomainName, args[0].toString()});
		log.setLog(logMessage);
		return log;
	}
	
	private SysLog makeUpdateLog(String messageCode, String domainName, Object[] args) {
		SysLog log = new SysLog();
		String i18nDomainName = messageProvider.getMessage("domain." + domainName);
		String logMessage = messageProvider.getMessage(messageCode, new Object[]{i18nDomainName, args[0].toString()});
		log.setLog(logMessage);
		return log;
	}	
	private SysLog makeSuccessLog( ProceedingJoinPoint joinPoint) {
		return makeLog(".succ", joinPoint);
	}
	
	private SysLog makeFailureLog( ProceedingJoinPoint joinPoint) {
		return makeLog(".failed", joinPoint);
	}
	
	private SysLog makeLog(String resultSuffix, ProceedingJoinPoint joinPoint) {
		SysLog log = null;
		MethodSignature methodSignature = (MethodSignature)joinPoint.getSignature();
		Method method = methodSignature.getMethod();
		String methodName = method.getName();
		Object[] args = joinPoint.getArgs();
		String domainName = getDomainName(joinPoint);
		if(methodName.equals("create")) {
			log = makeCreateLog("operation.log.create" + resultSuffix, domainName, args);
		} else if(methodName.equals("delete")) {
			log = makeDeleteLog("operation.log.delete" + resultSuffix, domainName, args);
		} else if(methodName.startsWith("get") || methodName.startsWith("find")) {
			if(!domainName.equals("SysLog")) {
				log = makeQueryLog("operation.log.query" + resultSuffix, domainName, args);
			}
		} else if(methodName.equals("update")){
			log = makeUpdateLog("operation.log.update" + resultSuffix, domainName, args);
		} else {
			log = new SysLog();
			log.setLog("domainName:" + domainName + ";Method:" + methodName);
		}
		if(log == null) {
			return null;
		}
		log.setType(SysLog.TYPE_OP);
		SecurityContext securityContext = SecurityContextHolder.getContext();
		Authentication authentication = securityContext.getAuthentication();
		if(authentication != null) {
			log.setUserName(authentication.getName());
		} else {
			log.setUserName("anonymous");
		}
		return log;
	}
	
	
	@Around("this(com.yangjie.common.service.Service) and not (this(com.yangjie.common.syslog.SysLogService) and execution(* create(..)))")
	public Object logger(ProceedingJoinPoint joinPoint) throws Throwable {
		try {
			Object retval = joinPoint.proceed();
			SysLog log = makeSuccessLog(joinPoint);
			logger.debug(log);
			try {
				if(log != null) {
					service.create(log);
				}
			} catch(Exception e) {
				e.printStackTrace();
				logger.debug(e.getMessage());
			}
			return retval;
		} catch (Throwable e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			SysLog log = makeFailureLog(joinPoint);
			logger.debug(log);
			try {
				if(log != null) {
					service.create(log);
				}
			} catch(Exception e2) {
				e2.printStackTrace();
				logger.debug(e2.getMessage());
			}			
			throw e;
		}
	}
}
